package com.bolins.examples.subspringside.servlet;

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.octo.captcha.service.CaptchaService;
import com.octo.captcha.service.CaptchaServiceException;

/**
 * Jcaptcha验证码
 * 
 * @author liuys
 * 
 */
@SuppressWarnings("serial")
public class JcaptchaServlet extends HttpServlet {
	private static final Logger logger = LoggerFactory
			.getLogger(JcaptchaServlet.class);

	private static final String SERVICE_NAME_ID = "captchaService";
	private static final String PARAM_CAPTCHA_NAME = "captchaParameterName";
	private static final String DEFAULT_CAPTCHA_PARAMETER_NAME = "j_captcha";
	private static final String AUTO_PASS = "autoPass";
	private static final String VALIDATE_FILTER_PATH = "validateFilterPath";

	private static final String DEFAULT_VALIDATE_FILTER_PATH = "/jcaptcha_check";
	private static final String RESPONSE_PATH = "/index.jsp";

	private String capthchaParameterName = DEFAULT_CAPTCHA_PARAMETER_NAME;
	private String validateFilterPath = DEFAULT_VALIDATE_FILTER_PATH;
	private String autoPass;

	private CaptchaService captchaService;

	@Override
	public void init(ServletConfig config) throws ServletException {
		initParameters(config);
		initService(config);
	}

	protected void initParameters(ServletConfig config) {
		if (StringUtils.isNotBlank(config.getInitParameter(PARAM_CAPTCHA_NAME))) {
			capthchaParameterName = config.getInitParameter(PARAM_CAPTCHA_NAME);
		}

		if (StringUtils.isNotBlank(config.getInitParameter(AUTO_PASS))) {
			autoPass = config.getInitParameter(AUTO_PASS);
		}

		if (StringUtils.isNotBlank(config
				.getInitParameter(VALIDATE_FILTER_PATH))) {
			validateFilterPath = config.getInitParameter(VALIDATE_FILTER_PATH);
		}
	}

	protected void initService(ServletConfig config) {
		ApplicationContext ac = WebApplicationContextUtils
				.getWebApplicationContext(config.getServletContext());
		captchaService = (CaptchaService) ac.getBean(SERVICE_NAME_ID);
	}

	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		this.doGet(req, resp);
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String servletPath = req.getServletPath();

		// 验证码检验路径
		if (StringUtils.startsWith(servletPath, validateFilterPath)) {
			boolean validate = validateCaptchaChallenge(req);
			if (validate) {
				req.setAttribute("check", "success");
			} else {
				req.setAttribute("check", "error");
			}
			req.getRequestDispatcher(RESPONSE_PATH).forward(req, resp);
			// 验证码生成路径
		} else {
			generateCaptchaImage(req, resp);
		}
	}

	protected void generateCaptchaImage(HttpServletRequest req,
			HttpServletResponse resp) throws IOException {
		// 确保Captcha Test的安全性、可靠性
		resp.setHeader("Cache-Control", "no-store");
		resp.setHeader("Pragma", "no-cache");
		resp.setDateHeader("Expires", 0);

		// 输出JPEG图片
		resp.setContentType("image/jpeg");

		ServletOutputStream out = resp.getOutputStream();
		try {
			String captchaId = req.getSession(true).getId();
			BufferedImage challenge = (BufferedImage) captchaService
					.getChallengeForID(captchaId, req.getLocale());
			ImageIO.write(challenge, "jpg", out);
			out.flush();
		} catch (CaptchaServiceException e) {
			logger.error(e.getMessage(), e);
		} finally {
			out.close();
		}
	}

	protected boolean validateCaptchaChallenge(final HttpServletRequest req) {
		String captchaId = req.getSession().getId();
		String captchaChallonge = req.getParameter(capthchaParameterName);

		if (StringUtils.isNotBlank(captchaChallonge)
				&& StringUtils.equals(autoPass, captchaChallonge)) {
			return true;
		}

		return captchaService
				.validateResponseForID(captchaId, captchaChallonge);
	}

	@Override
	public void destroy() {
		captchaService = null;
	}

}
